package com.mhh.selary.backend.domain.api;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mhh.sdk.beans.dto.BaseItemDTO;
import com.mhh.sdk.beans.dto.http.BaseResponseDTO;
import com.mhh.sdk.beans.enums.http.HttpMediaTypeEnum;
import com.mhh.sdk.beans.enums.http.HttpMethodEnum;
import com.mhh.sdk.beans.enums.http.HttpParamTypeEnum;
import com.mhh.sdk.beans.enums.http.HttpStatusEnum;
import com.mhh.sdk.utils.beans.BeanCopyUtils;
import com.mhh.sdk.utils.http.AbstractCommonRequest;
import com.mhh.sdk.utils.structure.DataUtils;
import com.mhh.selary.backend.config.EnvPropConfig;
import com.mhh.selary.backend.dao.entity.api.SelaryApiHttpEntity;
import com.mhh.selary.backend.dao.entity.api.SelaryApiHttpParamEntity;
import com.mhh.selary.backend.dto.api.ApiHttpRunResultDTO;
import com.mhh.selary.backend.enums.MediaTypeEnum;
import com.mhh.selary.backend.enums.ParamTypeEnum;
import com.mhh.selary.backend.enums.ProtocolEnum;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author mhh
 * @date 2020-10-29 15:40:37
 */
public class ApiHttpDomain {

    private Long envId;

    private SelaryApiHttpEntity httpEntity;

    private List<SelaryApiHttpParamEntity> paramList;

    private List<SelaryApiHttpParamEntity> headerList;

    private AbstractCommonRequest request;

    public static ApiHttpDomain init(Long envId, SelaryApiHttpEntity httpEntity, List<SelaryApiHttpParamEntity> paramEntityList) {
        ApiHttpDomain domain = new ApiHttpDomain();
        domain.envId = envId;
        domain.httpEntity = httpEntity;
        if (CollectionUtils.isNotEmpty(paramEntityList)) {
            Map<Integer, List<SelaryApiHttpParamEntity>> paramGroupMap = paramEntityList.stream().collect(Collectors.groupingBy(SelaryApiHttpParamEntity::getParamType));
            domain.paramList = paramGroupMap.get(ParamTypeEnum.PARAMS.getType());
            domain.headerList = paramGroupMap.get(ParamTypeEnum.HEADER.getType());
        }
        return domain;
    }

    public ApiHttpRunResultDTO send() {
        this.generatorRequest();
        this.generatorUrl();
        this.generatorHeader();
        this.generatorParam();
        this.generatorBody();
        return this.generatorResult();
    }

    private ApiHttpRunResultDTO generatorResult() {
        BaseResponseDTO baseResponseDTO = request.call(0).getResponseDTO();
        ApiHttpRunResultDTO resultDTO = BeanCopyUtils.copyObject(baseResponseDTO, ApiHttpRunResultDTO.class);
        Integer httpCode = baseResponseDTO.getHttpCode();
        String httpStatus = String.valueOf(httpCode);
        HttpStatusEnum httpStatusEnum = HttpStatusEnum.valueBy(httpCode);
        if (httpStatusEnum != null) {
            httpStatus += " " + httpStatusEnum.getDesc();
        }
        resultDTO.setHttpStatus(httpStatus);
        resultDTO.setSuccess(HttpStatusEnum.OK.getStatus().equals(httpCode));
        List<BaseItemDTO> requestHeaders = resultDTO.getRequestHeaders();
        if (requestHeaders == null) {
            requestHeaders = Lists.newArrayList();
        }
        requestHeaders.add(0, BaseItemDTO.builder().itemCode("Host").itemName(baseResponseDTO.getHost()).build());
        requestHeaders.add(1, BaseItemDTO.builder().itemCode("Content-Type").itemName(baseResponseDTO.getContentType()).build());
        resultDTO.setRequestHeaders(requestHeaders);

        if (baseResponseDTO.getContentType().contains("application/json")) {
            String responseContent = baseResponseDTO.getResponseContent();
            resultDTO.setResponseContent(DataUtils.prettyJson(responseContent));
        }
        return resultDTO;
    }

    private void generatorRequest() {
        MediaTypeEnum mediaTypeEnum = MediaTypeEnum.valueBy(httpEntity.getRequestType());
        request = new AbstractCommonRequest() {
            @Override
            protected void generatorRequest() {
                if (MediaTypeEnum.PARAMS == mediaTypeEnum) {
                    requestDTO.setParamType(HttpParamTypeEnum.PARAMS);
                    requestDTO.setMedia(HttpMediaTypeEnum.X_WWW_FORM_URLENCODED);
                } else if (MediaTypeEnum.APPLICATION_X_WWW_FORM_URLENCODED == mediaTypeEnum) {
                    requestDTO.setParamType(HttpParamTypeEnum.BODY);
                    requestDTO.setMedia(HttpMediaTypeEnum.X_WWW_FORM_URLENCODED);
                } else if (MediaTypeEnum.APPLICATION_JSON == mediaTypeEnum) {
                    requestDTO.setParamType(HttpParamTypeEnum.BODY);
                    requestDTO.setMedia(HttpMediaTypeEnum.JSON);
                } else if (MediaTypeEnum.TEXT_PLAIN == mediaTypeEnum) {
                    requestDTO.setParamType(HttpParamTypeEnum.BODY);
                    requestDTO.setMedia(HttpMediaTypeEnum.TEXT_PLAIN);
                } else if (MediaTypeEnum.MULTIPART_FORM_DATA == mediaTypeEnum) {
                    requestDTO.setParamType(HttpParamTypeEnum.BODY);
                    requestDTO.setMedia(HttpMediaTypeEnum.MULTIPART_FORM_DATA);
                }
                requestDTO.setMethod(HttpMethodEnum.valueBy(httpEntity.getMethod()));
            }
        };
    }

    private void generatorUrl() {
        ProtocolEnum protocol = ProtocolEnum.valueBy(httpEntity.getProtocol());
        String url = protocol.getProtocol() + "://" + EnvPropConfig.replaceHolder(envId, httpEntity.getApiUrl());
        request.url(url);
    }

    private void generatorBody() {
        request.body(EnvPropConfig.replaceHolder(envId, httpEntity.getRequestBody()));
    }

    private void generatorParam() {
        if (paramList == null) {
            return;
        }
        Map<String, String> paramMap = paramList.stream().collect(
                Collectors.toMap(
                        entity -> EnvPropConfig.replaceHolder(envId, entity.getParamKey()),
                        entity -> EnvPropConfig.replaceHolder(envId, entity.getParamValue())));
        request.param(paramMap);
    }

    private void generatorHeader() {
        Map<String, Object> paramMap = Maps.newHashMap();
        if (headerList != null) {
            paramMap = headerList.stream().collect(
                    Collectors.toMap(
                            entity -> EnvPropConfig.replaceHolder(envId, entity.getParamKey()),
                            entity -> EnvPropConfig.replaceHolder(envId, entity.getParamValue())));
        }
        if (!paramMap.containsKey("User-Agent")) {
            paramMap.put("User-Agent", "Selary/1.0.0");
        }
        request.header(paramMap);
    }
}
